#!/usr/bin/env python
# -*- coding: utf-8 -*-

from typing import Dict, List, Set, Optional, Tuple
import logging
from tree_sitter import Tree, Node
# 导入数据结构
from parser.refactor.data_structures import (
    ClassInfo, ParserContext, DependencyContext, DependencyType,
    MethodInfo, FieldInfo, AnnotationInfo, GraphNodeInfo, GraphEdgeInfo,
    MetadataInfo, RelationshipInfo, RelationshipCollection,
    ClassType, Visibility, FileInfo, ParameterInfo, CommentInfo
)
from parser.refactor.java_metadata_extractor.java_metadata_extractor import JavaMetadataExtractor
from parser.refactor.java_node_type import (JavaNodeType)

logger = logging.getLogger(__name__)


class JavaMethodExtractor(JavaMetadataExtractor):
    """Java方法元数据提取器"""

    def __init__(self, class_name_map: Dict[str, ClassInfo]):
        """
        初始化Java解析器

        Args:
            class_name_map: # 类名到类信息的映射
        """
        super().__init__()
        self.class_name_map = class_name_map

    def extract_method_info(self, file_path: str, node: Node, code_bytes: bytes,
                            package_name: str, import_list: List[str]) -> MethodInfo:
        """
            从方法声明节点提取方法信息

            Args:
                file_path: 源文件路径
                node: 方法声明节点
                code_bytes: 源代码字节
                package_name: 包名
                import_list: import列表

            Returns:
                MethodInfo对象

            Raises:
                ValueError: 无法获取必要的方法信息时
            """
        try:
            # 1. 提取方法名
            method_name = None
            for child in node.children:
                if child.type == JavaNodeType.IDENTIFIER:
                    method_name = self.get_node_text(child, code_bytes)
                    break

            if not method_name:
                raise ValueError("无法获取方法名")

            # 2. 提取修饰符
            modifiers = set()
            visibility = Visibility.PACKAGE  # 默认包可见性

            modifier_node = None
            for child in node.children:
                if child.type == JavaNodeType.MODIFIERS:
                    modifier_node = child
                    break

            if modifier_node:
                modifier_text = self.get_node_text(modifier_node, code_bytes)
                modifiers = set(modifier_text.split())

                # 设置可见性
                if 'public' in modifiers:
                    visibility = Visibility.PUBLIC
                elif 'protected' in modifiers:
                    visibility = Visibility.PROTECTED
                elif 'private' in modifiers:
                    visibility = Visibility.PRIVATE

            # 3. 提取返回类型
            return_type = None
            is_constructor = True  # 默认假设是构造函数

            for child in node.children:
                if JavaNodeType.is_return_type(child.type):
                    return_type = self.get_node_text(child, code_bytes)
                    is_constructor = False
                    break

            # 4. 提取参数信息
            parameters = self._extract_parameters(node, code_bytes, package_name, import_list)

            # 5. 提取抛出的异常
            throws = self._extract_exceptions_full_name(node, code_bytes, package_name, import_list)

            # 6. 提取方法上的注解
            annotations = self._extract_annotations_full_name(node, code_bytes, package_name, import_list)

            # 7. 构建完全限定名
            containing_class = self._get_containing_class_name(node, code_bytes)
            if containing_class:
                if package_name:
                    full_name = f"{package_name}.{containing_class}#{method_name}{parameters}"
                else:
                    full_name = f"{containing_class}#{method_name}{parameters}"
            else:
                full_name = f"{method_name}{parameters}"

            # 8. 获取源代码
            source_code = self.get_node_text(node, code_bytes)

            # 8. 创建并返回MethodInfo对象
            return MethodInfo(
                name=method_name,
                full_name=full_name,
                return_type=return_type,
                visibility=visibility,
                is_static='static' in modifiers,
                is_abstract='abstract' in modifiers,
                is_constructor=is_constructor,
                parent_class=containing_class,
                parameters=parameters,
                throws=throws,
                annotations=annotations,
                body=source_code
            )

        except Exception as e:
            logger.error(f"提取方法信息时出错 {file_path}: {str(e)}")
            raise

    def _extract_parameters(self, node: Node, code_bytes: bytes,
                            package_name: str, import_list: List[str]) -> str:
        """提取方法参数信息"""
        parameters = []

        # 查找形参列表节点
        formal_parameters = None
        for child in node.children:
            if child.type == JavaNodeType.FORMAL_PARAMETERS:
                formal_parameters = child
                break

        if formal_parameters:
            for child in formal_parameters.children:
                if child.type == JavaNodeType.FORMAL_PARAMETER:
                    # 获取参数类型
                    type_node = next((c for c in child.children
                                      if JavaNodeType.is_parameter_type(c.type)), None)

                    if type_node :
                        # 提取参数类型的全限定名
                        parameter_full_name = self.extract_full_name_by_imports(
                            self.get_node_text(type_node, code_bytes),
                            package_name,
                            import_list,
                            self.class_name_map)
                        parameters.append(parameter_full_name)

        parameters_str = ""
        if parameters:
            for param in parameters:
                parameters_str += param + ","
            parameters_str = "(" + parameters_str[:-1] + ")"
        else:
            parameters_str = "()"

        return parameters_str

    def _extract_exceptions_full_name(self, node: Node, code_bytes: bytes,
                                      package_name: str, import_list: List[str]) -> List[str]:
        """提取方法抛出的异常"""
        exceptions = []

        # 查找throws子句
        throws_node = None
        for child in node.children:
            if child.type == JavaNodeType.THROWS:
                throws_node = child
                break

        if throws_node:
            for child in throws_node.children:
                if child.type in (JavaNodeType.TYPE_IDENTIFIER, JavaNodeType.SCOPED_TYPE_IDENTIFIER):
                    exception_name = self.get_node_text(child, code_bytes)
                    exception_full_name = self.extract_full_name_by_imports(
                                exception_name,
                                package_name,
                                import_list,
                                self.class_name_map)
                    exceptions.append(exception_full_name)

        return exceptions

    def _extract_annotations_full_name(self, node: Node, code_bytes: bytes,
                                      package_name: str, import_list: List[str]) -> List[str]:
        """
        提取方法的注解全限定名列表

        Args:
            node: 方法声明节点
            code_bytes: 源代码字节
            package_name: 当前包名
            import_list: import语句列表

        Returns:
            List[str]: 注解全限定名列表
        """
        annotations = []

        try:
            # 查找修饰符节点（包含注解）
            modifier_node = None
            for child in node.children:
                if child.type == JavaNodeType.MODIFIERS:
                    modifier_node = child
                    break

            if not modifier_node:
                return annotations

            # 遍历所有注解节点
            for child in modifier_node.children:
                if child.type == JavaNodeType.ANNOTATION_DECLARATION:
                    # 提取注解名称
                    annotation_name = None
                    for anno_child in child.children:
                        if anno_child.type == JavaNodeType.IDENTIFIER:
                            annotation_name = self.get_node_text(anno_child, code_bytes)
                            break

                    if not annotation_name:
                        continue

                    # 解析注解的全限定名
                    annotation_full_name = self.extract_full_name_by_imports(
                        annotation_name,
                        package_name,
                        import_list,
                        self.class_name_map
                    )

                    annotations.append(annotation_full_name)

            return annotations

        except Exception as e:
            logger.error(f"提取注解信息时出错: {str(e)}")
            return []

    def _get_containing_class_name(self, node: Node, code_bytes: bytes) -> Optional[str]:
        """获取包含该方法的类名"""
        current = node
        while current.parent:
            current = current.parent
            if JavaNodeType.is_class_declaration(current.type):
                for child in current.children:
                    if child.type == JavaNodeType.IDENTIFIER:
                        return self.get_node_text(child, code_bytes)
        return None


